package al.xc.common.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.*;
import java.util.function.Function;
import java.util.zip.CRC32;

/**
 * 通用工具类
 */
public class CommonUtils {

    public static <K,V> Map<K,V> makeMap(K[] keys, V[] values) {
        return makeMap(keys, values, true);
    }

    public static <K,V> Map<K,V> makeMap(K[] keys, V[] values, boolean excludeNull) {
        if (null == keys || null == values) {
            throw new IllegalArgumentException("keys or values cannot is null");
        }
        if (keys.length != values.length) {
            throw new IllegalArgumentException("keys.size need equal values.size");
        }
        Map<K, V> result = new HashMap<>(keys.length);
        for (int i = 0; i < keys.length; ++i) {
            if (null == keys[i] || null == values[i]) {
                continue;
            }
            result.put(keys[i], values[i]);
        }
        return result;
    }

    /**
     * 分组
     * @param list 源列表
     * @param result 结果
     * @param function 属性方法
     * @param <T> 数据类型
     * @param <R> 属性方法返回类型
     */
    public static <T, R> void group(List<T> list, Map<R, List<T>> result, Function<T, R> function) {
        if (null == list || null == result || null == function) {
            return;
        }

        List<T> sublist;
        for (T single : list) {
            R key = function.apply(single);
            sublist = result.computeIfAbsent(key, k -> new ArrayList<>());
            sublist.add(single);
        }
    }

    /**
     * 获取单列值
     * @param list 源列表
     * @param function 属性方法
     * @param <T> 数据类型
     * @param <R> 属性方法返回类型
     * @return 返回结果数组
     */
    public static <T, R> List<R> single(List<T> list, Function<T, R> function) {
        if (null == list || null == function) {
            return null;
        }

        List<R> result = new ArrayList<>();
        for (T single : list) {
            result.add(function.apply(single));
        }
        return result;
    }

    /**
     * 查询值
     * @param list 源列表
     * @param findFunc 查找属性方法
     * @param findVl 查找值
     * @param resultFunc 结果属性方法
     * @param <T> 数据类型
     * @param <R> 查找属性返回类型
     * @param <V> 结果属性返回类型
     * @return
     */
    public static <T, R, V> V find(List<T> list, Function<T, R> findFunc, R findVl, Function<T, V> resultFunc) {
        if (null == list || null == findFunc || null == resultFunc) {
            return null;
        }

        for (T single : list) {
            if (findFunc.apply(single).equals(findVl)) {
                return resultFunc.apply(single);
            }
        }
        return null;
    }

    /**
     * 查询值
     * @param list 源列表
     * @param findFunc 查找属性方法
     * @param findVl 查找值
     * @param <T> 数据类型
     * @param <R> 查找属性返回类型
     * @return
     */
    public static <T, R> T find(List<T> list, Function<T, R> findFunc, R findVl) {
        if (null == list || null == findFunc) {
            return null;
        }

        for (T single : list) {
            if (findFunc.apply(single).equals(findVl)) {
                return single;
            }
        }
        return null;
    }

    /**
     * 合并
     * @param list 源列表
     * @param sep 分隔符
     * @param <T> 数据类型
     * @return 返回合并后的字符串
     */
    public static <T> String merge(List<T> list, String sep) {
        if (null == list) return null;

        StringBuilder result = new StringBuilder();
        for(T single : list) {
            result.append(single.toString());
            result.append(sep);
        }
        return result.substring(0, result.length()-1);
    }

    /**
     * 相加的接口类
     * @param <T>
     */
    public interface Plus<T> {
        T run(T left, T right);
    }

    /**
     * 计算总值
     * @param list 源列表
     * @param vlFunc 属性值方法
     * @param <T> 对象类型
     * @param <R> 值类型
     * @return 所有值总和
     */
    public static <T, R> R sum(List<T> list, Function<T, R> vlFunc, Plus<R> plus) {
        R result = null;
        if (null == list) {
            return result;
        }
        for (T single : list) {
            if (null == result) {
                result = vlFunc.apply(single);
            } else {
                result = plus.run(result, vlFunc.apply(single));
            }
        }
        return result;
    }

    /**
     * 获取md5
     * @param src
     * @return
     */
    public static String md5(String src) {
        try {
            MessageDigest m = MessageDigest.getInstance("MD5");
            m.update(src.getBytes("UTF8"));
            return bytes2string16(m.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static String bytes2string16(byte[] src) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0 ;i < src.length; ++i) {
            sb.append(String.format("%02x", src[i]));
        }
        return sb.toString();
    }

    /**
     * 计算crc32
     * @param vl
     * @return
     */
    public static int crc32(String vl) {
        CRC32 crc32 = new CRC32();
        crc32.update(vl.getBytes());
        int result = (int)crc32.getValue();
        return Math.abs(result);
    }

    /**
     * 判断字符串是否为空
     * @param vl
     * @return
     */
    public static boolean isNullOrEmpty(String vl) {
        return (null == vl || vl.equals(""));
    }

    /**
     * 读取完整的流数据
     * @param stream
     * @return
     * @throws IOException
     */
    public static byte[] readStream(InputStream stream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        while((len = stream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        outStream.close();
        return outStream.toByteArray();
    }
}
